"""Book service for managing classical literature.

Handles book CRUD operations, search, and content management.
"""

from __future__ import annotations

import json
import logging
from typing import List, Optional, Dict, Any, Tuple
from pathlib import Path
import jieba
from sqlalchemy.orm import Session
from sqlalchemy import or_, func

from app.models.book_model import Book
from app.schemas.book import (
    BookCreate,
    BookUpdate,
    BookSearchResult,
    BookOut,
    BookCategory,
)
from app.config import settings


logger = logging.getLogger(__name__)


class BookService:
    """Book management service."""

    def __init__(self):
        # 初始化jieba分词
        jieba.initialize()

    def get_books(
        self,
        db: Session,
        page: int = 1,
        page_size: int = 20,
        category: Optional[str] = None,
        dynasty: Optional[str] = None,
        difficulty: Optional[str] = None,
        keyword: Optional[str] = None,
    ) -> BookSearchResult:
        """获取书籍列表（支持分页和筛选）"""
        try:
            query = db.query(Book)

            # 筛选条件
            if category:
                query = query.filter(Book.category == category)
            if dynasty:
                query = query.filter(Book.dynasty == dynasty)
            if difficulty:
                query = query.filter(Book.difficulty == difficulty)
            if keyword:
                # 搜索标题、作者、描述
                search_filter = or_(
                    Book.title.contains(keyword),
                    Book.author.contains(keyword),
                    Book.description.contains(keyword),
                )
                query = query.filter(search_filter)

            # 计算总数
            total = query.count()

            # 分页
            offset = (page - 1) * page_size
            books = query.offset(offset).limit(page_size).all()

            total_pages = (total + page_size - 1) // page_size

            pydantic_items = [BookOut.model_validate(book) for book in books]
            return BookSearchResult(
                items=pydantic_items,
                total=total,
                page=page,
                page_size=page_size,
                total_pages=total_pages,
            )

        except Exception as e:
            logger.error(f"Failed to get books: {e}")
            return BookSearchResult(
                items=[], total=0, page=page, page_size=page_size, total_pages=0
            )

    def get_book_by_id(self, db: Session, book_id: int) -> Optional[Book]:
        """根据ID获取书籍详情"""
        try:
            return db.query(Book).filter(Book.id == book_id).first()
        except Exception as e:
            logger.error(f"Failed to get book {book_id}: {e}")
            return None

    def get_book_by_book_id(self, db: Session, book_id: str) -> Optional[Book]:
        """根据book_id获取书籍详情"""
        try:
            return db.query(Book).filter(Book.book_id == book_id).first()
        except Exception as e:
            logger.error(f"Failed to get book {book_id}: {e}")
            return None

    def create_book(self, db: Session, book_data: BookCreate) -> Optional[Book]:
        """创建新书籍"""
        try:
            db_book = Book(**book_data.dict())
            db.add(db_book)
            db.commit()
            db.refresh(db_book)
            return db_book
        except Exception as e:
            logger.error(f"Failed to create book: {e}")
            db.rollback()
            return None

    def update_book(
        self, db: Session, book_id: int, book_update: BookUpdate
    ) -> Optional[Book]:
        """更新书籍信息"""
        try:
            db_book = self.get_book_by_id(db, book_id)
            if not db_book:
                return None

            update_data = book_update.dict(exclude_unset=True)
            for field, value in update_data.items():
                setattr(db_book, field, value)

            db.commit()
            db.refresh(db_book)
            return db_book

        except Exception as e:
            logger.error(f"Failed to update book {book_id}: {e}")
            db.rollback()
            return None

    def delete_book(self, db: Session, book_id: int) -> bool:
        """删除书籍"""
        try:
            db_book = self.get_book_by_id(db, book_id)
            if not db_book:
                return False

            db.delete(db_book)
            db.commit()
            return True

        except Exception as e:
            logger.error(f"Failed to delete book {book_id}: {e}")
            db.rollback()
            return False

    def search_books(
        self, db: Session, keyword: str, page: int = 1, page_size: int = 20
    ) -> BookSearchResult:
        """全文搜索书籍"""
        try:
            # 使用jieba分词提高搜索准确性
            keywords = list(jieba.cut(keyword))

            query = db.query(Book)

            # 构建搜索条件
            search_conditions = []
            for kw in keywords:
                if len(kw.strip()) > 0:
                    condition = or_(
                        Book.title.contains(kw),
                        Book.author.contains(kw),
                        Book.description.contains(kw),
                        Book.category.contains(kw),
                        Book.dynasty.contains(kw),
                    )
                    search_conditions.append(condition)

            if search_conditions:
                query = query.filter(or_(*search_conditions))

            total = query.count()
            offset = (page - 1) * page_size
            books = query.offset(offset).limit(page_size).all()

            total_pages = (total + page_size - 1) // page_size

            pydantic_items = [BookOut.model_validate(book) for book in books]
            return BookSearchResult(
                items=pydantic_items,
                total=total,
                page=page,
                page_size=page_size,
                total_pages=total_pages,
            )

        except Exception as e:
            logger.error(f"Failed to search books: {e}")
            return BookSearchResult(
                items=[], total=0, page=page, page_size=page_size, total_pages=0
            )

    def get_categories(self, db: Session) -> List[BookCategory]:
        """获取书籍分类统计"""
        try:
            result = (
                db.query(Book.category, func.count(Book.id).label("count"))
                .group_by(Book.category)
                .all()
            )

            return [
                BookCategory(name=category, count=count) for category, count in result
            ]

        except Exception as e:
            logger.error(f"Failed to get categories: {e}")
            return []

    def load_books_from_json(
        self, db: Session, data_dir: Optional[str] = None, overwrite: bool = False
    ) -> Dict[str, Any]:
        """从JSON文件加载或更新书籍数据（支持覆盖与绝对路径）。

        参数:
            db: 数据库 session
            data_dir: 书籍 JSON 目录，若未提供使用 settings.BOOKS_DATA_DIR
            overwrite: True 时若书籍已存在则覆盖更新（包括content与统计字段）

        返回:
            dict: {
                "directory": 使用的目录,
                "files_total": 文件总数,
                "loaded": 成功新建数量,
                "updated": 覆盖更新数量,
                "skipped": 跳过数量,
                "errors": [ {file, error} ... ]
            }
        """
        summary = {
            "directory": None,
            "files_total": 0,
            "loaded": 0,
            "updated": 0,
            "skipped": 0,
            "errors": [],  # type: ignore
        }
        try:
            base_dir = data_dir or settings.BOOKS_DATA_DIR
            data_path = Path(base_dir).resolve()
            summary["directory"] = str(data_path)

            if not data_path.exists() or not data_path.is_dir():
                logger.warning(f"Books data directory not found: {data_path}")
                return summary

            json_files = list(data_path.glob("*.json"))
            summary["files_total"] = len(json_files)

            for json_file in json_files:
                try:
                    with open(json_file, "r", encoding="utf-8") as f:
                        book_data = json.load(f)

                    # 基础校验
                    required_fields = ["id", "title", "author", "dynasty", "category"]
                    missing = [fld for fld in required_fields if fld not in book_data]
                    if missing:
                        raise ValueError(f"Missing required fields: {missing}")

                    # 统计字段自动计算（若未提供或为0）
                    chapters = book_data.get("chapters") or []
                    if not book_data.get("totalChapters"):
                        book_data["totalChapters"] = len(chapters)
                    if not book_data.get("totalCharacters"):
                        # 粗略统计：所有章节原文段落字符总和
                        total_chars = 0
                        for ch in chapters:
                            sections = ch.get("sections") or []
                            for sec in sections:
                                paragraphs = sec.get("paragraphs") or []
                                for p in paragraphs:
                                    original = p.get("original") or ""
                                    total_chars += len(original.replace("\n", ""))
                        book_data["totalCharacters"] = total_chars

                    existing_book = self.get_book_by_book_id(db, book_data["id"])

                    if existing_book and not overwrite:
                        logger.info(
                            f"Book {book_data['id']} exists, skip (overwrite=False)"
                        )
                        summary["skipped"] += 1
                        continue

                    if existing_book and overwrite:
                        # 覆盖更新
                        existing_book.title = book_data["title"]
                        existing_book.subtitle = book_data.get("subtitle")
                        existing_book.author = book_data["author"]
                        existing_book.dynasty = book_data["dynasty"]
                        existing_book.category = book_data["category"]
                        existing_book.description = book_data.get("description")
                        existing_book.total_chapters = book_data.get("totalChapters", 0)
                        existing_book.total_characters = book_data.get(
                            "totalCharacters", 0
                        )
                        existing_book.cover = book_data.get("cover")
                        existing_book.difficulty = book_data.get("difficulty", "中等")
                        existing_book.language = book_data.get("language", "古汉语")
                        existing_book.tags = book_data.get("tags")
                        existing_book.content = book_data
                        db.commit()
                        db.refresh(existing_book)
                        summary["updated"] += 1
                        logger.info(f"Updated book: {book_data['id']}")
                        continue

                    # 创建新书
                    book_create = BookCreate(
                        book_id=book_data["id"],
                        title=book_data["title"],
                        subtitle=book_data.get("subtitle"),
                        author=book_data["author"],
                        dynasty=book_data["dynasty"],
                        category=book_data["category"],
                        description=book_data.get("description"),
                        total_chapters=book_data.get("totalChapters", 0),
                        total_characters=book_data.get("totalCharacters", 0),
                        cover=book_data.get("cover"),
                        difficulty=book_data.get("difficulty", "中等"),
                        language=book_data.get("language", "古汉语"),
                        tags=book_data.get("tags"),
                        content=book_data,
                    )
                    if self.create_book(db, book_create):
                        summary["loaded"] += 1
                        logger.info(f"Loaded book: {book_data['title']}")
                except Exception as e:
                    err_msg = f"Failed to process {json_file.name}: {e}"
                    logger.error(err_msg)
                    summary["errors"].append({"file": json_file.name, "error": str(e)})
                    db.rollback()
                    continue

            return summary
        except Exception as e:
            logger.error(f"Failed to load books from JSON: {e}")
            summary["errors"].append({"file": None, "error": str(e)})
            return summary

    def extract_key_concepts(self, book: Book) -> List[Dict[str, str]]:
        """提取书籍的关键概念"""
        try:
            concepts = []

            if (book.content is not None) and isinstance(book.content, dict):
                chapters = book.content.get("chapters", [])
                for chapter in chapters:
                    key_entities = chapter.get("keyEntities", [])
                    for entity in key_entities:
                        concepts.append(
                            {
                                "name": entity.get("name", ""),
                                "type": entity.get("type", ""),
                                "description": entity.get("description", ""),
                                "chapter": chapter.get("title", ""),
                            }
                        )

            return concepts

        except Exception as e:
            logger.error(f"Failed to extract key concepts: {e}")
            return []

    def get_book_content_by_chapter(
        self, book: Book, chapter_id: Optional[int] = None
    ) -> Optional[Dict[str, Any]]:
        """获取书籍的章节内容"""
        try:
            if (book.content is None) or (not isinstance(book.content, dict)):
                return None

            chapters = book.content.get("chapters", [])

            if chapter_id is None:
                # 返回所有章节
                return {
                    "book_info": {
                        "title": book.title,
                        "author": book.author,
                        "dynasty": book.dynasty,
                    },
                    "chapters": chapters,
                }
            else:
                # 返回指定章节
                for chapter in chapters:
                    if chapter.get("id") == chapter_id:
                        return {
                            "book_info": {
                                "title": book.title,
                                "author": book.author,
                                "dynasty": book.dynasty,
                            },
                            "chapter": chapter,
                        }

                return None

        except Exception as e:
            logger.error(f"Failed to get book content: {e}")
            return None


# 全局服务实例
book_service = BookService()
